package cn.me.fdfs.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
import ch.ethz.ssh2.StreamGobbler;

/**
 * 
 * @author tozhangwj
 *
 */
public class JsshProxy {

  public static enum FileType {
    SHELL, CONFIG, LIB, LOG, WAR
  }

  public static String ClientPath = "/usr/local/vagent/";
  public static String ClientShellPath = "/usr/local/vagent/bin/";
  public static String ClientLibPath = "/usr/local/vagent/lib/";
  public static String ClientConfPath = "/usr/local/vagent/conf/";
  public static String ClientLogPath = "/usr/local/vagent/log/";
  public static String ClientWarPath = "/usr/local/vagent/war/";

  private int authType;// 1=passwd,2=id_dsa文件

  private String ip;
  private String username;
  private String passwd;
  private int port;

  private String dsaPath;

  private JSch jsch = new JSch();


  public JsshProxy(String ip, String username, String passwd, int port) {
    this.ip = ip;
    this.username = username;
    this.passwd = passwd;
    this.port = port;
    authType = 1;
  }

  public JsshProxy(String ip, String username, int port, String dsaPath) throws JSchException {
    this.ip = ip;
    this.username = username;
    this.port = port;
    this.dsaPath = dsaPath;
    jsch.addIdentity(dsaPath);
    authType = 2;
  }


  public CommandMessage updateFile(FileType type, File shellFile) {
    CommandMessage cm = new CommandMessage();
    cm.setCmdString("upload " + shellFile.getName());
    long start = System.currentTimeMillis();
    Session session = null;
    ChannelSftp c = null;
    if (shellFile != null && shellFile.canRead() && shellFile.isFile()) {
      try {
        session = jsch.getSession(username, ip, port);
        if (authType == 1) {
          session.setPassword(passwd);
        }

        session.setUserInfo(new SftpUserInfo());

        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);

        cm.setExecuteDate(System.currentTimeMillis());

        session.connect();
        c = (ChannelSftp) session.openChannel("sftp");
        c.connect();

        String distpath = "";
        switch (type) {
          case SHELL:
            distpath = ClientShellPath;
            break;
          case CONFIG:
            distpath = ClientConfPath;
            break;
          case LIB:
            distpath = ClientLibPath;
            break;
          case LOG:
            distpath = ClientLogPath;
            break;
          case WAR:
            distpath = ClientWarPath;
            break;
          default:
            break;
        }
        try {
          c.mkdir(ClientPath);
        } catch (SftpException e1) {
          // e1.printStackTrace();
        }
        try {
          c.mkdir(distpath);
        } catch (SftpException e1) {
          // e1.printStackTrace();
        }


        // List<Object> ls = c.ls("/usr/local/va*");
        // for(Object obj : ls){
        // System.out.println(obj);
        // }
        c.put(shellFile.getAbsolutePath(), distpath + shellFile.getName(), ChannelSftp.OVERWRITE);
        if (type == FileType.SHELL) {
          c.chmod(755, distpath + shellFile.getName());
        }

        cm.setType(CommandMessage.MessageType.OK);
        cm.setMessage("更新文件 ( " + shellFile.getAbsolutePath() + " ) 成功");

      } catch (JSchException e) {
        cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
        cm.setMessage(e.getMessage());
        e.printStackTrace();
      } catch (SftpException e) {
        cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
        cm.setMessage(e.getMessage());
        e.printStackTrace();
      } finally {
        if (c != null) {
          c.disconnect();
          c.exit();
        }
        if (session != null) {
          session.disconnect();
        }
        cm.setExecuteTime(System.currentTimeMillis() - start);
      }
    } else {
      cm.setType(CommandMessage.MessageType.ERROR);
      cm.setMessage("File error:" + shellFile);
    }
    return cm;
  }

  public CommandMessage execute(String shellName) {
    CommandMessage cm = new CommandMessage();
    cm.setCmdString(shellName);
    long start = System.currentTimeMillis();
    Session session = null;
    ChannelExec c = null;
    InputStream in = null;

    try {
      session = jsch.getSession(username, ip, port);
      if (authType == 1) {
        session.setPassword(passwd);
      }

      session.setUserInfo(new SftpUserInfo());

      java.util.Properties config = new java.util.Properties();
      config.put("StrictHostKeyChecking", "no");
      session.setConfig(config);

      cm.setExecuteDate(System.currentTimeMillis());

      session.connect();

      c = (ChannelExec) session.openChannel("exec");
      c.setCommand(shellName);
      c.setInputStream(null);


      in = c.getInputStream();

      c.connect();

      InputStream is = new StreamGobbler(c.getInputStream());
      BufferedReader brs = new BufferedReader(new InputStreamReader(is));

      for (String line = brs.readLine(); line != null; line = brs.readLine()) {

        cm.getExecuteLines().add(line);
      }
      cm.setType(CommandMessage.MessageType.OK);



    } catch (JSchException e) {
      cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
      cm.setMessage(e.getMessage());
    } catch (IOException e) {
      cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
      cm.setMessage(e.getMessage());
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

      if (c != null) {
        c.disconnect();
      }
      if (session != null) {
        session.disconnect();
      }
      cm.setExecuteTime(System.currentTimeMillis() - start);
    }
    return cm;
  }


  public CommandMessage executeCommand(String cmdString, List<String> par) {
    CommandMessage cm = new CommandMessage();
    cm.setCmdString(cmdString);
    long start = System.currentTimeMillis();
    Session session = null;
    ChannelExec c = null;
    InputStream in = null;
    ByteArrayOutputStream baos = null;
    try {
      session = jsch.getSession(username, ip, port);
      if (authType == 1) {
        session.setPassword(passwd);
      }

      session.setUserInfo(new SftpUserInfo());

      java.util.Properties config = new java.util.Properties();
      config.put("StrictHostKeyChecking", "no");
      session.setConfig(config);

      cm.setExecuteDate(System.currentTimeMillis());

      session.connect(1000);

      c = (ChannelExec) session.openChannel("exec");
      c.setCommand(cmdString);

      baos = new ByteArrayOutputStream();
      c.setOutputStream(baos);
      c.setErrStream(baos);
      in = c.getInputStream();
      StringBuilder sb = new StringBuilder();
      c.connect();
      if (par != null) {
        for (String p : par) {
          c.getOutputStream().write((p + "\n").getBytes());
          c.getOutputStream().flush();
          try {
            Thread.sleep(500);
          } catch (Exception ee) {
          }
        }
      }

      byte[] tmp = new byte[1024];
      while (true) {
        while (in.available() > 0) {
          int i = in.read(tmp, 0, 1024);
          if (i < 0)
            break;
          sb.append(new String(tmp, 0, i));
          // System.out.println(sb);
        }
        if (c.isClosed()) {
          // System.out.println("exit-status: "+c.getExitStatus());
          break;
        }
        try {
          Thread.sleep(200);
        } catch (Exception ee) {
        }
      }

      String message = baos.toString("utf-8");
      if (message.length() > 0) {
        cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
        cm.setMessage(message);
      } else {
        cm.setType(CommandMessage.MessageType.OK);
        cm.setMessage(sb.toString());
      }


    } catch (JSchException e) {
      cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
      cm.setMessage(e.getMessage());
    } catch (IOException e) {
      cm.setType(CommandMessage.MessageType.CLIENT_ERROR);
      cm.setMessage(e.getMessage());
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
      if (baos != null) {
        try {
          baos.close();
        } catch (IOException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }
      if (c != null) {
        c.disconnect();
      }
      if (session != null) {
        session.disconnect();
      }
      cm.setExecuteTime(System.currentTimeMillis() - start);
    }
    return cm;
  }

  public CommandMessage updatePasswd(String newPasswd) {
    CommandMessage cm;
    if (authType == 1) {
      cm = executeCommand("echo " + username + ":" + passwd + " | chpasswd", null);
      this.passwd = newPasswd;
    } else {
      cm = new CommandMessage();
      cm.setExecuteDate(System.currentTimeMillis());
      cm.setCmdString("passwd");
      cm.setMessage("登录类型位RSA登录");
      cm.setType(CommandMessage.MessageType.ERROR);
    }
    return cm;
  }


  // get

  public String getIp() {
    return ip;
  }

  public String getUsername() {
    return username;
  }

  public String getPasswd() {
    return passwd;
  }

  public int getPort() {
    return port;
  }

  private static class SftpUserInfo implements UserInfo, UIKeyboardInteractive {
    public String getPassword() {
      return passwd;
    }

    public void setPassword(String passwd) {
      this.passwd = passwd;
    }

    public boolean promptYesNo(String str) {
      return true;
    }

    String passwd;

    public String getPassphrase() {
      return null;
    }

    public boolean promptPassphrase(String message) {
      return true;
    }

    public boolean promptPassword(String message) {
      return true;
    }

    public void showMessage(String message) {

    }

    public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt,
        boolean[] echo) {

      return null; // cancel
    }
  }

}
